﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;


namespace eBrain
{
    public partial class Exp_Saccade : Experiment
    {
        //public enum SaccadeStatus { WaitingToCenter, WaitingStimulus, WaitingTimeout, Timeout };
        //public SaccadeStatus ASStatus;



        public Exp_Saccade(TestControlWindow _tcw, ExperimentMainForm _expw)//, int _w, int _h)
            : base(_tcw, _expw)//, _w, _h) 
        {}

        public Exp_Saccade(ExperimentMainForm _expw, string datapath, string logpath, string sInputMode)
            : base(_expw, datapath, logpath, sInputMode)//, _w, _h) 
        { }

        //--------------------------------------------
        //   Saccade-Antisaccade
        //--------------------------------------------
        DateTime dtExpectedTriggerTime;
        DateTime TriggerAppearTime;
        public int SaccadeThreshold = 0;
        public DateTime SaccadeThreshCrossTime = DateTime.MinValue;
        public int iTriggerDelay; //Ritardo nella comparsa dello stimolo di trigger

        public Image CenterImg, SaccadeTriggerImg, AntisaccadeTriggerImg;
        public Bitmap CanvasCenterOnly, CanvasCenterRightSaccade, CanvasCenterLeftSaccade, CanvasCenterRightAntisaccade, CanvasCenterLeftAntisaccade;

        public string[] TypeStrArray = { "S", "A" };
        public string[] SideStrArray = { "L", "R" };

        public const int SACCADE = 0, ANTISACCADE = 1;
        public const int LEFT = 0, RIGHT = 1; 
        public int TriggerType; 

        public override void CustomXMLLoad(XmlDocument xmldoc)
        {

            int x, y, h, w, x0, y0, x1, y1, x2, y2;
            string sx, sy;

            SaccadeThreshold = int.Parse(xmldoc.SelectSingleNode("Experiment/SaccadeThreshold").InnerText);
            CenterImg = Image.FromFile(sImagePath + xmldoc.SelectSingleNode("Experiment/img_center").InnerText);
            SaccadeTriggerImg = Image.FromFile(sImagePath + xmldoc.SelectSingleNode("Experiment/img_saccade").InnerText);
            AntisaccadeTriggerImg = Image.FromFile(sImagePath + xmldoc.SelectSingleNode("Experiment/img_antisaccade").InnerText);

            CanvasCenterOnly = new Bitmap(ScreenWidth, ScreenHeight);
            CanvasCenterRightSaccade = new Bitmap(ScreenWidth, ScreenHeight);
            CanvasCenterLeftSaccade = new Bitmap(ScreenWidth, ScreenHeight);
            CanvasCenterRightAntisaccade = new Bitmap(ScreenWidth, ScreenHeight);
            CanvasCenterLeftAntisaccade = new Bitmap(ScreenWidth, ScreenHeight);

            //Preparo l'immagine con il solo centro
            Graphics g = Graphics.FromImage(CanvasCenterOnly);
            g.Clear(bkgrnd);

            w = int.Parse(ROIs.Item(0).SelectSingleNode("w").InnerText.ToString());
            h = int.Parse(ROIs.Item(0).SelectSingleNode("h").InnerText.ToString());

            sx = ROIs.Item(0).SelectSingleNode("x").InnerText.ToString();
            sy = ROIs.Item(0).SelectSingleNode("y").InnerText.ToString();

            x = int.Parse(sx.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));
            y = int.Parse(sy.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));

            x0 = (x * ScreenWidth) / 100 - w / 2;
            y0 = (y * ScreenHeight) / 100 - h / 2;

            g.DrawImageUnscaled(CenterImg, x0, y0);
            g.Dispose();

            //Preparo l'immagine del trigger a sinistra (Saccade)
            Graphics g1 = Graphics.FromImage(CanvasCenterLeftSaccade);
            g1.Clear(bkgrnd);

            g1.DrawImageUnscaled(CenterImg, x0, y0);

            sx = ROIs.Item(1).SelectSingleNode("x").InnerText.ToString();
            sy = ROIs.Item(1).SelectSingleNode("y").InnerText.ToString();

            x = int.Parse(sx.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));
            y = int.Parse(sy.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));

            x1 = (x * ScreenWidth) / 100 - w / 2;
            y1 = (y * ScreenHeight) / 100 - h / 2;

            g1.DrawImageUnscaled(SaccadeTriggerImg, x1, y1);
            g1.Dispose();

            //Preparo l'immagine del trigger a destra (Saccade)
            Graphics g2 = Graphics.FromImage(CanvasCenterRightSaccade);
            g2.Clear(bkgrnd);

            g2.DrawImageUnscaled(CenterImg, x0, y0);

            sx = ROIs.Item(2).SelectSingleNode("x").InnerText.ToString();
            sy = ROIs.Item(2).SelectSingleNode("y").InnerText.ToString();

            x = int.Parse(sx.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));
            y = int.Parse(sy.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));

            x2 = (x * ScreenWidth) / 100 - w / 2;
            y2 = (y * ScreenHeight) / 100 - h / 2;

            g2.DrawImageUnscaled(SaccadeTriggerImg, x2, y2);
            g2.Dispose();

            //Preparo l'immagine del trigger a sinistra (Antisaccade)
            Graphics g3 = Graphics.FromImage(CanvasCenterLeftAntisaccade);
            g3.Clear(bkgrnd);

            g3.DrawImageUnscaled(CenterImg, x0, y0);

            sx = ROIs.Item(1).SelectSingleNode("x").InnerText.ToString();
            sy = ROIs.Item(1).SelectSingleNode("y").InnerText.ToString();

            x = int.Parse(sx.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));
            y = int.Parse(sy.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));

            x1 = (x * ScreenWidth) / 100 - w / 2;
            y1 = (y * ScreenHeight) / 100 - h / 2;

            g3.DrawImageUnscaled(AntisaccadeTriggerImg, x1, y1);
            g3.Dispose();

            //Preparo l'immagine del trigger a destra(Antisaccade)
            Graphics g4 = Graphics.FromImage(CanvasCenterRightAntisaccade);
            g4.Clear(bkgrnd);

            g4.DrawImageUnscaled(CenterImg, x0, y0);

            sx = ROIs.Item(2).SelectSingleNode("x").InnerText.ToString();
            sy = ROIs.Item(2).SelectSingleNode("y").InnerText.ToString();

            x = int.Parse(sx.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));
            y = int.Parse(sy.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, ""));

            x2 = (x * ScreenWidth) / 100 - w / 2;
            y2 = (y * ScreenHeight) / 100 - h / 2;

            g4.DrawImageUnscaled(AntisaccadeTriggerImg, x2, y2);
            g4.Dispose();

            DelayedStimulusTimer = new System.Timers.Timer();
            DelayedStimulusTimer.Elapsed += new System.Timers.ElapsedEventHandler(DelayedStimulusTimer_Elapsed);
            DelayedStimulusTimer.AutoReset = false;
            //base.CustomXMLLoad();
        }

            public override void TimeoutTimer_Elapsed(object obj, EventArgs e)
        {
            TimeoutTimer.Stop();
            myExpW.ClearScreen();
            myExpW.Invalidate();

            System.Diagnostics.Process myProcess = System.Diagnostics.Process.GetCurrentProcess();
            myProcess.PriorityClass = System.Diagnostics.ProcessPriorityClass.Normal;

            myResultList.Add(new ResultListElement(iTrialValue, sTrialOutcome, iTriggerDelay.ToString() + "-" + TypeStrArray[TriggerType] + "-" + SideStrArray[TriggerSide]));

            myLog.Log("Trial " + ActualTrialNumber.ToString() + " Timout : ");

            if (bUseSounds)
            {
                //SoundPlayer sp = new SoundPlayer(Properties.Resources.selection);
                SPSelection.Play();
            }

            //<DataViewer>
            if (bEyelinkConnected)
                ET.SendCommand("TRIAL_RESULT 0");

            if (bTrainingMode)
            {
                if (++ActualTrialNumber >= TrainingTrials.Count)
                    FromTrainingToTrials();
                else
                {
                    DoNextTrial();
                }

            }
            else
            {
                if (++ActualTrialNumber >= Trials.Count)
                {
                    ActualTrialNumber = Trials.Count - 1;
                    EndOfTrials = true;

                    //SaveResults();
                    EndOfTest();
                }
                else
                {
                    DoNextTrial();
                }
            }
        }

        public void DelayedStimulusTimer_Elapsed(object obj, EventArgs e)
        {
            TriggerAppearTime = DateTime.Now;
            DelayedStimulusTimer.Stop();
            //ASStatus = SaccadeStatus.WaitingTimeout;

            if (TriggerSide == LEFT && TriggerType == SACCADE)
            {
                myExpW.CopyImage(CanvasCenterLeftSaccade);
                    }
            else
            {
                if (TriggerSide == RIGHT && TriggerType == SACCADE)
                {
                    myExpW.CopyImage(CanvasCenterRightSaccade);
                }
                else
                {
                    if (TriggerSide == LEFT && TriggerType == ANTISACCADE)
                    {
                        myExpW.CopyImage(CanvasCenterLeftAntisaccade);
                    }
                    else
                    {
                        if (TriggerSide == RIGHT && TriggerType == ANTISACCADE)
                        {
                            myExpW.CopyImage(CanvasCenterRightAntisaccade);
                        }
                    }
                }
            }

            myExpW.Invalidate();
            if (ExpInputMode == InputMode.Eyetracker && bEyelinkConnected)
            {
                ET.SendMessage("SYNCTIME");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        public override void UpdateCoordTimerElapsedEvent(object sender, EventArgs e)
        {
            float x = 0, y = 0;
            int act_x = 0, act_y = 0;
            bool new_data = false;
            DateTime dt_now = DateTime.Now;
            //Meccanismo di acquisizione delle coordinate di riferimento
            //controllo che non sia scaduto il timeout
            //TimeSpan ts = DateTime.Now - StartTime;

            //this.Invoke(new EventHandler(delegate { myTCW.UpdateTime(); }));

            switch (ExpInputMode)
            {

                case InputMode.MouseEmulation:

                    //Sto usando il mouse in emulazione dell'ET
                    act_x = System.Windows.Forms.Cursor.Position.X;
                    act_y = System.Windows.Forms.Cursor.Position.Y;
                    x = act_x;
                    y = act_y;
                    new_data = true;
                    break;

                case InputMode.Eyetracker:
                    try
                    {
                        ET.UpdateGaze(ref act_x, ref act_y);
                        new_data = true;
                    }
                    catch (Exception ex)
                    {
                        myLog.Log("MyTimerElapsedEvent Error: " + ex.Message.ToString() + "\r\n" + ex.StackTrace);
                        MessageBox.Show("MyTimerElapsedEvent Error: " + ex.Message.ToString() + "\r\n" + ex.StackTrace);
                    }

                    break;

                case InputMode.Touch:
                    break;
            }

            //aggiorno la differenza soltanto se ho un dato nuovo
            if (new_data)
            {
                if (last_x > -1000)
                {
                    delta_x = act_x - last_x;
                    last_x = act_x;

                    //Console.WriteLine("delta_x =" + delta_x.ToString());

                    //mi sono mosso verso destra
                    if (delta_x >= SaccadeThreshold)
                    {
                        if (SaccadeThreshCrossTime == DateTime.MinValue)
                        {
                            SaccadeThreshCrossTime = dt_now;
                            if (TriggerSide == LEFT)
                                sTrialOutcome = "A";
                            else
                                sTrialOutcome = "S";

                            iTrialValue = (int)(SaccadeThreshCrossTime - TriggerAppearTime).TotalMilliseconds;

                            //Aggiorno il punteggio
                            if ((TriggerType == ANTISACCADE && sTrialOutcome == "A") || (TriggerType == SACCADE && sTrialOutcome == "S"))
                                TrialScore++;
                        }
                    }

                    //mi sono mosso verso sinistra
                    else if (delta_x <= -SaccadeThreshold)
                    {
                        if (SaccadeThreshCrossTime == DateTime.MinValue)
                        {
                            SaccadeThreshCrossTime = dt_now;
                            if (TriggerSide == RIGHT)
                                sTrialOutcome = "A";
                            else
                                sTrialOutcome = "S";

                            iTrialValue = (int)(SaccadeThreshCrossTime - TriggerAppearTime).TotalMilliseconds;

                            //Aggiorno il punteggio
                            if ((TriggerType == ANTISACCADE && sTrialOutcome == "A") || (TriggerType == SACCADE && sTrialOutcome == "S"))
                                TrialScore++;
                        }
                    }
                }
                else
                {
                    last_x = act_x;
                }
            }
        }


        public override void Custom_DoNextTrial()
        {
            SaccadeThreshCrossTime = DateTime.MinValue;
            last_x = -1000;
            sTrialOutcome = "N";
            iTrialValue = 0;
            //TrialStartTime = DateTime.Now;

            myExpW.ClearScreen();
            myExpW.Invoke(new EventHandler(delegate { myExpW.Refresh(); }));

            Thread.Sleep(500);

            //ASStatus = SaccadeStatus.WaitingToCenter;

            XmlNodeList TrialList;  

            if (bTrainingMode)
            
                TrialList = TrainingTrials;
            else 
                TrialList = Trials;

            iTriggerDelay = int.Parse(TrialList.Item(ActualTrialNumber).SelectSingleNode("Delay").InnerText.ToString());

            if (TrialList.Item(ActualTrialNumber).SelectSingleNode("TargetPosition").InnerText.ToString() == "left")
                    TriggerSide = 0;
                else
                    TriggerSide = 1;


            if (TrialList.Item(ActualTrialNumber).SelectSingleNode("Type").InnerText.ToString() == "saccade")
                TriggerType = SACCADE;
            else
                TriggerType = ANTISACCADE;


            last_x = -1000;
            exp_status = ExperimentStatus.BlackScreen;

            myExpW.CopyImage(CanvasCenterOnly);
            myExpW.Invalidate();


            //alzo la priorità del processo
            System.Diagnostics.Process myProcess = System.Diagnostics.Process.GetCurrentProcess();
            myProcess.PriorityClass = System.Diagnostics.ProcessPriorityClass.High;

            
            //Thread.Sleep(500);

            //myExpW.CopyImage(CanvasCenterLeftAntisaccade);
            //myExpW.Invalidate();
            //Thread.Sleep(500);

            //myExpW.CopyImage(CanvasCenterLeftSaccade);
            //myExpW.Invalidate();
            //Thread.Sleep(500);

            //myExpW.CopyImage(CanvasCenterRightAntisaccade);
            //myExpW.Invalidate();
            //Thread.Sleep(500);

            //myExpW.CopyImage(CanvasCenterRightSaccade);
            //myExpW.Invalidate();
            //Thread.Sleep(500);

            //AwakeWait(500);
            //ASStatus = SaccadeStatus.WaitingStimulus;
            //exp_status = ExperimentStatus.DoingTrials;
            DelayedStimulusTimer.Interval = iTriggerDelay;
            DelayedStimulusTimer.Start();

            dtExpectedTriggerTime = DateTime.Now.AddMilliseconds(iTriggerDelay);

        }


        /// <summary>
        /// Fa partire il timer periodico di aggiornamento delle coordinate schermo lette (dal mouse o dall'Eyelink)
        /// </summary>
        public override void StartPeriodicTimer()
        {
            CoordUpdateTimer.Elapsed += new System.Timers.ElapsedEventHandler(UpdateCoordTimerElapsedEvent);
            CoordUpdateTimer.Interval = ScanPeriodMs;
            CoordUpdateTimer.Start();

            myLog.Log("Timer Started");

        }

        public override void StopPeriodicTimer()
        {
            CoordUpdateTimer.Stop();
            CoordUpdateTimer.Elapsed -= UpdateCoordTimerElapsedEvent;
            myLog.Log("Timer Stopped");
        }
    }
}
